import flash.display.Sprite;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.KeyboardEvent;

import flash.geom.Point;
import flash.geom.Rectangle;
import flash.geom.Matrix;
import flash.utils.Timer;

import haxe.FastList;
import haxe.Timer;

import Kongregate;
import nme.Assets;
import TileModel;
import HealthBarView;

class TileModelContainer
{
  public var model:TileModel;
  public var camera:Rectangle;
  public var HealthBar:HealthBarView;
  public var HitArea:HitAreaView;
  public function new(inModel:TileModel,inCamera:Rectangle)
  {
    model = inModel;
    HealthBar = new HealthBarView(model,inCamera);
    HitArea = null;
  }
}
class BaseLevel extends Sprite
{
  private var myTimer:Timer;
  private static inline var MAX_TILE_SIZE:Int = 64;
  private var MAP_COLUMNS:Int;
  private var MAP_ROWS:Int;
  private var maxX:Float;
  private var minX:Float;
  public var DamageTaken:Int;
  private var kongVar : CKongregate;
  private var Difficulty:Int;
  
  //tile ID s in tile sheet
  private static inline var BOX:Int = 00;
  private static inline var BOSS:Int = 12;
  private static inline var SKY:Int = 10;
  private static inline var DOOR:Int = 13;
  private static inline var PLATFORM:Int = 11;
  private static inline var MACHINE_GUN:Int = 01;
  private static inline var PISTOL:Int = 02;
  private static inline var SHOTGUN:Int = 03;

  private static inline var PINK:Int = 21;
  //private static inline var BLUE:Int = 20;
  private static inline var FAIRY:Int = 30;
  private static inline var PINK_FAIRY = 22;
  private static inline var FLOWER = 31;
  private static inline var HEART = 32;
  private static inline var KITTY = 33;
  private var BLUE:Int;


  private static inline var PinkRadius:Float = 20.5;
  private static inline var BlueRadius:Float = 20.5;
  
  private var _platformMap:Array<Array<Int>>;
  private var _HeartMapUp:Array<Array<String>>; 
  private var _HeartMapDown:Array<Array<String>>; 
  private var _HeartMapLeft:Array<Array<String>>; 
  private var _HeartMapRight:Array<Array<String>>; 
  
  private var _collisionMap:Array<Array<List<TileModel>>>;
  private var _gameObjectMap:Array<Array<Int>>;
  
  //Create blank BitmapData objects as the canvas for the game
  private var _staticBackgroundBitmapData:BitmapData;
  private var _staticBackgroundBitmap:Bitmap;
  private var _backgroundBitmapData:BitmapData;
  private var _backgroundBitmap:Bitmap;
  private var _foregroundBitmapData:BitmapData;
  private var _foregroundBitmap:Bitmap;
  private var _tileSheetBitmapData:BitmapData;
  private var _currentGunBitmapData:BitmapData;
 private var _camera:Rectangle;

  private var _boxModel:MainCharacterModel;
  private var _bossModel:BossModel;
  private var _bossController:BossController;
  private var MainHealthBar:MainHealthBarView;
  private var MainHitAreaView:HitAreaView;
  private var MainHitAttackAreaView:HitAreaView;

  private var _bossHealth:BossHealthBarView;
  private var _gunModel:TileModel;
  private var _gunView:GunView;

  public var maxEnemiesOnScreen:Int;
  private var _enemies:FastList<TileModelContainer>;
  private var _enemiesReserve:FastList<TileModelContainer>;
  private var _MainCharacterController:MainCharacterController;
  private var _MainCharacterView:MainCharacterView;

  private var shotVector:VectorModel;
  private var shotVectorView:VectorView;
  private var shotModel:TileModel;

//   private var platform1:VectorModel;
//   private var platform1View:VectorView;
//   private var platform2:VectorModel;
//   private var platform2View:VectorView;
//   private var platformAngle:Float;
//   private var platformVelocity:Float;
      
  //Create a collision Controller to handle the collision
  //between the player and the platformss
  private var _collisionController:TileCollisionController;
    
  private var _currentTile:Int;
  private var _mapRow:Int;
  private var _mapColumn:Int;
  
  public var volume:Bool;
  public var sound:Bool;
  private var mKeyDown:Array<Bool>;
  private var Pause:String;
  public var pauseMenu:PauseMenu;

  public function new(stage:Dynamic){
  super();
  //load Constants
  BLUE = Constants.BLUEPLATFORM;
  
  _enemies = new FastList<TileModelContainer>();
 _enemiesReserve = new FastList<TileModelContainer>();
  _currentTile = 0;
  _mapRow = 0;
  _mapColumn = 0;
  MAP_COLUMNS = 10;
  MAP_ROWS = 8;
  minX = 0;
  maxX = Constants.flashWidth*99;
  maxEnemiesOnScreen = 10;
  _tileSheetBitmapData = Assets.getBitmapData("assets/TileSheet.png");
  _currentGunBitmapData =Assets.getBitmapData("assets/MachineGun.png");
  _collisionController = new TileCollisionController();

  _staticBackgroundBitmapData = Assets.getBitmapData("Cardboard_Background.png");
  _staticBackgroundBitmap = new Bitmap(_staticBackgroundBitmapData);

  _backgroundBitmapData = new BitmapData(MAP_COLUMNS * MAX_TILE_SIZE, 
          MAP_ROWS * MAX_TILE_SIZE, true, 0);
  _backgroundBitmap = new Bitmap(_backgroundBitmapData);

  _foregroundBitmapData = new BitmapData(MAP_COLUMNS * MAX_TILE_SIZE, 
          MAP_ROWS * MAX_TILE_SIZE, true, 0);
  _foregroundBitmap = new Bitmap(_foregroundBitmapData);
  _camera = new Rectangle (0, 0, Constants.flashWidth, Constants.flashHeight);

    addChild(_staticBackgroundBitmap);
    addChild(_backgroundBitmap);
    addChild(_foregroundBitmap);

    shotVector  = new VectorModel();
    shotVectorView = new VectorView(shotVector, _camera, 1);
    addChild(shotVectorView);

  
    mKeyDown = [];
    Pause = "UnPaused";
    pauseMenu = new PauseMenu();
    pauseMenu.addEventListener("Quit",onQuit);
    stage.addEventListener(KeyboardEvent.KEY_DOWN, OnKeyDown );
    stage.addEventListener(KeyboardEvent.KEY_UP, OnKeyUp );
    }

  public function onQuit(event:Event)
  {
    removeChild(pauseMenu);
    this.removeEventListener(Event.ENTER_FRAME, OnEnter);
    UnLoad();
    dispatchEvent(new Event("LevelQuit"));
  }


public function OnKeyUp (event:KeyboardEvent)
    {
      mKeyDown[event.keyCode] = false;
      //lastUp = event.keyCode;
    }

public function OnKeyDown(event:KeyboardEvent)
   {
      // When a key is held down, multiple KeyDown events are generated.
      // This check means we only pick up the first one.
      if (!mKeyDown[event.keyCode])
      {
         // Store for use in game
         mKeyDown[event.keyCode] = true;
	  //I do this here, because if they hold down P,
	 // it won't pause and unpause constantly.
	  if(mKeyDown[ 80 ] == true)
	  {
	      mKeyDown[ 80 ] = false;
	      if(Pause == "Paused")
                {
                  Pause = "UnPaused";
		  removeChild(pauseMenu);
                }
              else 
                {
                  Pause = "Paused";
		  addChild(pauseMenu);
                }
	  }
      }
  }

public function Load(inVolume:Bool,inSound:Bool,inKongVar:CKongregate,inDifficulty:Int)
{
  DamageTaken = 0;
  volume = inVolume;
  sound = inSound;
  kongVar = inKongVar;
  Difficulty = inDifficulty;
  flash.Lib.current.addChild(this);
                  Pause = "UnPaused";
  if(this.contains(pauseMenu))
    {removeChild(pauseMenu);}
  this.addEventListener(Event.ENTER_FRAME, OnEnter);

  //This brings focus to the level
  stage.focus = stage;

  for(enemy in _enemies)
  {
    //addChild(enemy.HealthBar);
    //addChild(enemy.HitArea);
  }
  
}

  //abstract
  public function buildReserveEnemies()
  {

  }

  //Create tile Models and map them to the
  //correct positions on the tile sheet
  private function buildMap(map:Array<Array<Int>>)
  {
    for(mapColumn in 0...MAP_COLUMNS)
    {
      for(mapRow in 0...MAP_ROWS)
      {
	var currentTile:Int = map[mapRow][mapColumn];
	if(currentTile > -1)
	{
	  //Find the tile's column and row position
	  //on the tile sheet
	  var tileSheetColumn:Int = Std.int(currentTile / 10);
	  var tileSheetRow:Int = Std.int(currentTile % 10);
	    
	  switch(currentTile)
	  {
	    case BOSS:
	      _bossModel
		  = new BossModel
		  (
		    MAX_TILE_SIZE,
		    tileSheetColumn, tileSheetRow, 
		    mapRow, mapColumn, 
		    48, 48
		  ); 
		//Add some gravity  
		_bossModel.gravity_Vy = 0.98;
		//_bossController = new BossController(_bossModel);
		_bossModel.health = 105;
		_bossModel.MaxHealth = 105;
		if(Difficulty >= 3)
		{
		_bossModel.health = 210;
		_bossModel.MaxHealth = 210;
		}
		_bossHealth = new BossHealthBarView(_bossModel);
	    case BOX:
	      _boxModel
		  = new MainCharacterModel
		  (
		    MAX_TILE_SIZE,
		    tileSheetColumn, tileSheetRow, 
		    mapRow, mapColumn, 
		    48, 48
		  ); 
	
		//Add some gravity  
		_boxModel.gravity_Vy = 0.98;
		
		//Add the UIView and UIController  
		_MainCharacterController
		  = new MainCharacterController(_boxModel);
		  _MainCharacterView
			  = new MainCharacterView
			  (_boxModel, _MainCharacterController, stage);  
			
// 		MainHealthBar = new MainHealthBarView(_boxModel,_camera);
// 		addChild(MainHealthBar);


		
	
	    case PINK:
	      //just draw for now
              
	      var pinkModel = new TileModel
	      (
		MAX_TILE_SIZE,
		    tileSheetColumn, tileSheetRow, 
		    mapRow, mapColumn, 
		    41, 41,false, MAX_TILE_SIZE, MAX_TILE_SIZE
	      );
	      pinkModel.gravity_Vy = 0.98;
	      pinkModel.vx = -5;
	      pinkModel.friction = 1; 
	      //addChild(Circle);
	      pinkModel.ImageX = 11;
	      pinkModel.ImageY = 11;
	      pinkModel.ImageWidth = 41;
	      pinkModel.ImageHeight= 41;

	      pinkModel.MaxHealth = 5*Difficulty;
	      pinkModel.health = 5*Difficulty;
	      pinkModel.setY = pinkModel.yPos +PinkRadius;
	      pinkModel.setX = pinkModel.xPos +PinkRadius;
	      pinkModel.CharacterType = "Pink";
	      var pinkModelContainer = new TileModelContainer(pinkModel,_camera);
	     // addChild(pinkModelContainer.HealthBar);
	      _enemies.add(pinkModelContainer);
	      
	      drawGameObject(pinkModel,_foregroundBitmapData);
	    case BLUE:
	      var platform:TileModel 
	      = new TileModel
	      (
		MAX_TILE_SIZE,
		    tileSheetColumn, tileSheetRow, 
		    mapRow, mapColumn, 
		    MAX_TILE_SIZE, MAX_TILE_SIZE
	      );
		  drawGameObject(platform, _backgroundBitmapData);
	    
// 	    case BLUE:              
// 	      var pinkModel = new TileModel
// 	      (
// 		MAX_TILE_SIZE,
// 		    tileSheetColumn, tileSheetRow, 
// 		    mapRow, mapColumn, 
// 		    41, 41,false, MAX_TILE_SIZE, MAX_TILE_SIZE
// 	      );
// 	      pinkModel.gravity_Vy = 0.98;
// 	      //pinkModel.vx = -5;
// 	      pinkModel.friction = 1; 
// 	      //addChild(Circle);
// 	      pinkModel.ImageX = 11;
// 	      pinkModel.ImageY = 11;
// 	      pinkModel.ImageWidth = 41;
// 	      pinkModel.ImageHeight= 41;
// 
// 	      pinkModel.setY = pinkModel.yPos +BlueRadius;
// 	      pinkModel.setX = pinkModel.xPos +BlueRadius;
// 	      pinkModel.CharacterType = "Blue";
// 	      pinkModel.MaxHealth = 5*Difficulty;
// 	      pinkModel.health = 5*Difficulty;
// 	      var pinkModelContainer = new TileModelContainer(pinkModel,_camera);
// 	      addChild(pinkModelContainer.HealthBar);
// 	      _enemies.add(pinkModelContainer);
// 	      
// 	      drawGameObject(pinkModel,_foregroundBitmapData);
	    case FAIRY:
	      //just draw for now
              
	      var pinkModel = new TileModel
	      (
		MAX_TILE_SIZE,
		    tileSheetColumn, tileSheetRow, 
		    mapRow, mapColumn, 
		    41, 41,false, MAX_TILE_SIZE, MAX_TILE_SIZE
	      );
	      pinkModel.vx = -5;
	      pinkModel.vy = -5;
	      pinkModel.friction = 1; 
	      //addChild(Circle);
	      pinkModel.ImageX = 0;
	      pinkModel.ImageY = 0;
	      pinkModel.ImageXOffset = 11;
	      pinkModel.ImageYOffset = 11;
	      pinkModel.ImageWidth = 64;
	      pinkModel.ImageHeight= 64;

	      pinkModel.setY = pinkModel.yPos +PinkRadius;
	      pinkModel.setX = pinkModel.xPos +PinkRadius;
	      pinkModel.CharacterType = "Fairy";
	      pinkModel.MaxHealth = 5*Difficulty;
	      pinkModel.health = 5*Difficulty;
	      var pinkModelContainer = new TileModelContainer(pinkModel,_camera);
	      addChild(pinkModelContainer.HealthBar);
	      _enemies.add(pinkModelContainer);
	      
	      drawGameObject(pinkModel,_foregroundBitmapData);
	    case PINK_FAIRY:
	      //just draw for now
              
	      var pinkModel = new TileModel
	      (
		MAX_TILE_SIZE,
		    tileSheetColumn, tileSheetRow, 
		    mapRow, mapColumn, 
		    41, 41,false, MAX_TILE_SIZE, MAX_TILE_SIZE
	      );
	      pinkModel.vx = -5;
	      pinkModel.vy = -5;
	      pinkModel.friction = 1; 
	      //addChild(Circle);
	      pinkModel.ImageX = 0;
	      pinkModel.ImageY = 0;
	      pinkModel.ImageXOffset = 11;
	      pinkModel.ImageYOffset = 11;
	      pinkModel.ImageWidth = 64;
	      pinkModel.ImageHeight= 64;

	      pinkModel.setY = pinkModel.yPos +PinkRadius;
	      pinkModel.setX = pinkModel.xPos +PinkRadius;
	      pinkModel.CharacterType = "PinkFairy";
	      pinkModel.MaxHealth = 5*Difficulty;
	      pinkModel.health = 5*Difficulty;
	      var pinkModelContainer = new TileModelContainer(pinkModel,_camera);
	      addChild(pinkModelContainer.HealthBar);
	      _enemies.add(pinkModelContainer);
	      
	      drawGameObject(pinkModel,_foregroundBitmapData);
	    case FLOWER:
	      //just draw for now
              
	      var pinkModel = new TileModel
	      (
		MAX_TILE_SIZE,
		    tileSheetColumn, tileSheetRow, 
		    mapRow, mapColumn, 
		    41, 41,false, MAX_TILE_SIZE, MAX_TILE_SIZE
	      );
	      pinkModel.vx = -5;
	      pinkModel.vy = 0;
	      pinkModel.friction = 1; 
	      //addChild(Circle);
	      pinkModel.ImageX = 0;
	      pinkModel.ImageY = 0;
	      pinkModel.ImageXOffset = 11;
	      pinkModel.ImageYOffset = 11;
	      pinkModel.ImageWidth = 64;
	      pinkModel.ImageHeight= 64;

	      pinkModel.setY = pinkModel.yPos +PinkRadius;
	      pinkModel.setX = pinkModel.xPos +PinkRadius;
	      pinkModel.CharacterType = "Flower";
	      pinkModel.MaxHealth = 5*Difficulty;
	      pinkModel.health = 5*Difficulty;
	      var pinkModelContainer = new TileModelContainer(pinkModel,_camera);
	      addChild(pinkModelContainer.HealthBar);
	      _enemies.add(pinkModelContainer);
	      
	      drawGameObject(pinkModel,_foregroundBitmapData);

	    case HEART:
	      //just draw for now
              
	      var pinkModel = new TileModel
	      (
		MAX_TILE_SIZE,
		    tileSheetColumn, tileSheetRow, 
		    mapRow, mapColumn, 
		    41, 41,false, MAX_TILE_SIZE, MAX_TILE_SIZE
	      );
	      pinkModel.vx = 0;
	      pinkModel.vy = 0;
	      pinkModel.friction = 1; 
	      //addChild(Circle);
	      pinkModel.ImageX = 0;
	      pinkModel.ImageY = 0;
	      pinkModel.ImageXOffset = 11;
	      pinkModel.ImageYOffset = 11;
	      pinkModel.ImageWidth = 64;
	      pinkModel.ImageHeight= 64;

	      pinkModel.setY = pinkModel.yPos +PinkRadius;
	      pinkModel.setX = pinkModel.xPos +PinkRadius;
	      pinkModel.CharacterType = "Heart";
	      pinkModel.MaxHealth = 5*Difficulty;
	      pinkModel.health = 5*Difficulty;
	      var pinkModelContainer = new TileModelContainer(pinkModel,_camera);
	      addChild(pinkModelContainer.HealthBar);
	      _enemies.add(pinkModelContainer);
	      
	      drawGameObject(pinkModel,_foregroundBitmapData);

	    case KITTY:
	      //just draw for now
              
	      var pinkModel = new TileModel
	      (
		MAX_TILE_SIZE,
		    tileSheetColumn, tileSheetRow, 
		    mapRow, mapColumn, 
		    41, 41,false, MAX_TILE_SIZE, MAX_TILE_SIZE
	      );
	      pinkModel.gravity_Vy = 0.98;
	      pinkModel.vx = 0;
	      pinkModel.vy = 0;
	      pinkModel.friction = 1; 
	      //addChild(Circle);
	      pinkModel.ImageX = 0;
	      pinkModel.ImageY = 0;
	      pinkModel.ImageXOffset = 11;
	      pinkModel.ImageYOffset = 11;
	      pinkModel.ImageWidth = 64;
	      pinkModel.ImageHeight= 64;

	      pinkModel.setY = pinkModel.yPos +PinkRadius;
	      pinkModel.setX = pinkModel.xPos +PinkRadius;
	      pinkModel.CharacterType = "Kitty";
	      pinkModel.MaxHealth = 5*Difficulty;
	      pinkModel.health = 5*Difficulty;
	      var pinkModelContainer = new TileModelContainer(pinkModel,_camera);
	      addChild(pinkModelContainer.HealthBar);
	      _enemies.add(pinkModelContainer);
	      
	      drawGameObject(pinkModel,_foregroundBitmapData);
	    case PLATFORM:
	      var platform:TileModel 
	      = new TileModel
	      (
		MAX_TILE_SIZE,
		    tileSheetColumn, tileSheetRow, 
		    mapRow, mapColumn, 
		    MAX_TILE_SIZE, MAX_TILE_SIZE
	      );
		  drawGameObject(platform, _backgroundBitmapData);
	    
	    case SKY:
	      var sky:TileModel 
		= new TileModel
		(
		  MAX_TILE_SIZE,
		      tileSheetColumn, tileSheetRow, 
		    mapRow, mapColumn, 
		    MAX_TILE_SIZE, MAX_TILE_SIZE
		);
		  drawGameObject(sky, _backgroundBitmapData);
	    case DOOR:
	      var door:TileModel 
		= new TileModel
		(
		  MAX_TILE_SIZE,
		      tileSheetColumn, tileSheetRow, 
		    mapRow, mapColumn, 
		    MAX_TILE_SIZE, MAX_TILE_SIZE
		);
		drawGameObject(door, _backgroundBitmapData);

	  }  
	}
      }
    }
  }
    	  //Loads a tile from the tile sheet
	  //into the car Sprite's BitmapData obejct
	  private function loadTileIntoView
	    (tileModel:TileModel, bitmapData:BitmapData)
		{
		  var sourceRectangle:Rectangle = new Rectangle
  			(
  		    tileModel.tileSheetColumn * MAX_TILE_SIZE, 
  			  tileModel.tileSheetRow * MAX_TILE_SIZE, 
  			  tileModel.width, 
  			  tileModel.height
  			);
					
  	  var destinationPoint:Point = new Point(0, 0);
      
      bitmapData.copyPixels
        (
          _tileSheetBitmapData, 
          sourceRectangle, 
          destinationPoint,
          null, null, true
        );
	  }

      public function chasePlayer
	(
	  chasingObject:TileModel, 
	  targetObject:TileModel
	)
      {
	//Find the distance between the objects
	var vx:Float = targetObject.xPos - chasingObject.xPos;
	var vy:Float = targetObject.yPos - chasingObject.yPos;
	if(!getNewDirection(chasingObject))
	  {return;}
	if(vx < 5 && vx > -5)
	   vx = 0;
	if(vy < 5 && vy > -5)
	   vy = 0;
	//If the distance is greater on the x axis...
	if(Math.abs(vx) > Math.abs(vy))
	{
	  //Check whether to go left or right
	  if(vx < 0)
	  {
	    //Try and go left
	    if
	    (	   _platformMap[chasingObject.top][Math.floor((chasingObject.xPos - 1)/64)] != PLATFORM
		   && _platformMap[chasingObject.bottom][chasingObject.left] != PLATFORM
	    )
	    {
	      chasingObject.direction = "left";
	      chasingObject.vx = -5;
	      chasingObject.vy = 0;
	    }
          //Can't go Left, try vy
	    else
	    {
	      if(vy < 0)
	      {
	        //Try and go up
	        if
	          (
	            _platformMap[chasingObject.top][Math.floor((chasingObject.xPos+5)/MAX_TILE_SIZE)] != PLATFORM
		   && _platformMap[chasingObject.top][chasingObject.right] != PLATFORM
		  )
        	{
	          chasingObject.direction = "up";
    		    chasingObject.vx = 0;
    		    chasingObject.vy = -5;
	        }
	        else
	        {
		  chasingObject.changeDirection = "left";
		  findNewDirection(chasingObject);
	        }
	      }
	      else if(vy > 0)
	      {
	        //Try and go down
	        if
	          (_platformMap[chasingObject.bottom][Math.floor((chasingObject.xPos+5)/MAX_TILE_SIZE)] != PLATFORM
		   && _platformMap[chasingObject.bottom][chasingObject.right] != PLATFORM
        	  )
        	{
	          chasingObject.direction = "down";
    		    chasingObject.vx = 0;
    		    chasingObject.vy = 5;
	        }
	        else
	        {
		  chasingObject.changeDirection = "left";
		  findNewDirection(chasingObject);
	        }
	      }
	      else
	      {
		chasingObject.changeDirection = "left";
		findNewDirection(chasingObject);
	      }
	    }
	  }
	  else if(vx > 0)
	  {
	    //Try and go right
	    if
	      (_platformMap[Math.floor((chasingObject.yPos-chasingObject.vy)/MAX_TILE_SIZE)][Math.floor((chasingObject.xPos+chasingObject.width+4)/MAX_TILE_SIZE)] != PLATFORM
		&& _platformMap[Math.floor((chasingObject.yPos+chasingObject.height+chasingObject.vy)/MAX_TILE_SIZE)][Math.floor((chasingObject.xPos+chasingObject.width+4)/MAX_TILE_SIZE)] != PLATFORM
		    )
	    {
	      chasingObject.direction = "right";
	      chasingObject.vx = 5;
	      chasingObject.vy = 0;
	    }
	    //Can't go right try vy
	    else
	    {
	      if(vy < 0)
	      {
	        //Try and go up
	        if
	          (
	            _platformMap[chasingObject.top][chasingObject.left] != PLATFORM
		   && _platformMap[chasingObject.top][Math.floor((chasingObject.xPos + chasingObject.width-chasingObject.vx)/64)] != PLATFORM
        		)
        	{
	            chasingObject.direction = "up";
    		    chasingObject.vx = 0;
    		    chasingObject.vy = -5;
	        }
	        else
	        {
		  chasingObject.changeDirection = "right";
		  findNewDirection(chasingObject);
	        }
	      }
	      else if(vy > 0)
	      {
	        //Try and go down
	        if
	          (_platformMap[chasingObject.bottom][chasingObject.left] != PLATFORM
		   || _platformMap[chasingObject.bottom][chasingObject.right] != PLATFORM
        		)
        	{
		  if (_platformMap[chasingObject.bottom][chasingObject.left] == PLATFORM)
		      {
			chasingObject.vx = 1;
			chasingObject.vy = 0;
			chasingObject.direction = "right";
		      }
		  else if (_platformMap[chasingObject.bottom][chasingObject.right] == PLATFORM)
		      {
	    
			chasingObject.vx = -1;
			chasingObject.vy = 0;
			chasingObject.direction = "left";
		      }
		  else
		      {
			chasingObject.vx = 0;
			chasingObject.vy = 5;
			chasingObject.direction = "down";
		      }

	        }
	        else
	        {
		  chasingObject.changeDirection = "right";
		  findNewDirection(chasingObject);
	        }
	      }
	      else
	      {
		chasingObject.changeDirection = "right";
		findNewDirection(chasingObject);
	      }
	    }
	  }
	  }
	  //If the distance is greater on the y axis...
	  else
	  {
	    if(vy < 0)
	    {
	      //Try and go up
	      if
		(
		  _platformMap[Math.floor((chasingObject.yPos-4)/MAX_TILE_SIZE)][chasingObject.left] != PLATFORM
		  || _platformMap[Math.floor((chasingObject.yPos-4)/MAX_TILE_SIZE)][chasingObject.right] != PLATFORM
		      )
	      {
		  if (_platformMap[Math.floor((chasingObject.yPos-4)/MAX_TILE_SIZE)][chasingObject.left] == PLATFORM)
		      {
			chasingObject.vx = 5;
			chasingObject.vy = 0;
			chasingObject.direction = "right";
		      }
		  else if (_platformMap[Math.floor((chasingObject.yPos-4)/MAX_TILE_SIZE)][chasingObject.right] == PLATFORM)
		      {
	    
			chasingObject.vx = -5;
			chasingObject.vy = 0;
			chasingObject.direction = "left";
		      }
                  else
		{
		chasingObject.direction = "up";
		  chasingObject.vx = 0;
		  chasingObject.vy = -5;
		}
	      }
	      //Can't go up Try vx
	      else
	      {
		if(vx < 0)
		{
		  //Try and go left
		  if
		  (	_platformMap[chasingObject.top][Math.floor((chasingObject.xPos-1)/MAX_TILE_SIZE)] != PLATFORM
		      && _platformMap[chasingObject.bottom][Math.floor((chasingObject.xPos-1)/MAX_TILE_SIZE)] != PLATFORM
		  )
		  {
		    chasingObject.direction = "left";
		    chasingObject.vx = -5;
		    chasingObject.vy = 0;
		  }
		  else
		  {
		    chasingObject.changeDirection = "up";
		    findNewDirection(chasingObject);
		  }
		}
		else if(vx > 0)
		{
		  //Try and go right
		  if
		    (_platformMap[chasingObject.top][chasingObject.right] != PLATFORM
		    && _platformMap[chasingObject.bottom][chasingObject.right] != PLATFORM
			  )
		  {
		    chasingObject.direction = "right";
		    chasingObject.vx = 5;
		    chasingObject.vy = 0;
		  }
		  else
		  {
		      chasingObject.changeDirection = "up";
		      findNewDirection(chasingObject);
		  }
		
		}
		else
		{
		    chasingObject.changeDirection = "up";
		    findNewDirection(chasingObject);
		}
               }
              }
	      else if(vy > 0)
	      {
	        //Try and go down
	        if
	          (_platformMap[Math.floor((chasingObject.yPos+chasingObject.height+4)/MAX_TILE_SIZE)][chasingObject.left] != PLATFORM
		   || _platformMap[Math.floor((chasingObject.yPos+chasingObject.height+4)/MAX_TILE_SIZE)][chasingObject.right] != PLATFORM
        		)
        	{
		  if (_platformMap[Math.floor((chasingObject.yPos+chasingObject.height+4)/MAX_TILE_SIZE)][chasingObject.left] == PLATFORM)
		      {
			chasingObject.vx = 5;
			chasingObject.vy = 0;
			chasingObject.direction = "right";
		      }
		  else if (_platformMap[Math.floor((chasingObject.yPos+chasingObject.height+4)/MAX_TILE_SIZE)][chasingObject.right] == PLATFORM)
		      {
	    
			chasingObject.vx = -5;
			chasingObject.vy = 0;
			chasingObject.direction = "left";
		      }
                  else
		  {
	          chasingObject.direction = "down";
    		    chasingObject.vx = 0;
    		    chasingObject.vy = 5;
		  }
	        }
		//Can't go down. Try vx
	        else
	        {
		if(vx < 0)
		{
		  //Try and go left
		  if
		  (	_platformMap[chasingObject.top][chasingObject.left] != PLATFORM
		      && _platformMap[chasingObject.bottom][chasingObject.left] != PLATFORM
		  )
		  {
		    chasingObject.direction = "left";
		    chasingObject.vx = -5;
		    chasingObject.vy = 0;
		  }
		  else
		  {
		    chasingObject.changeDirection = "down";
		    findNewDirection(chasingObject);
		  }
		}
		else if(vx > 0)
		{
		  //Try and go right
		  if
		    (_platformMap[chasingObject.top][chasingObject.right] != PLATFORM
		    && _platformMap[chasingObject.bottom][chasingObject.right] != PLATFORM
			  )
		  {
		    chasingObject.direction = "right";
		    chasingObject.vx = 5;
		    chasingObject.vy = 0;
		  }
		  else
		  {
		      
		      chasingObject.changeDirection = "down";
		      findNewDirection(chasingObject);
		  }
		
		}
		else
		{
		    chasingObject.changeDirection = "down";
		    findNewDirection(chasingObject);
		}
	      }
	    }
	  }
    }
    
    public function getNewDirection(gameObject:TileModel)
    {
     var retval:Bool = false;
      switch(gameObject.direction)
      {
	case "left":
	    gameObject.vx = -5;
	    gameObject.vy = 0;
	case "right":
	    gameObject.vx = 5;
	    gameObject.vy = 0;
	case "up":
	    gameObject.vx = 0;
	    gameObject.vy = -5;
	case "down":
	    gameObject.vx = 0;
	    gameObject.vy = 5;

      }
// trace("gameObject.changeDirection: " + gameObject.changeDirection);
// trace("gameObject.direction: " + gameObject.direction);
      switch(gameObject.changeDirection)
      {
	case "1":
	{
	gameObject.changeDirection = "";
	}
	case "2":
	  {
	  
	  gameObject.changeDirection = "1";
	  }
	case "up":
	{
	  if(_platformMap[Math.floor((gameObject.yPos-4)/MAX_TILE_SIZE)][gameObject.left] != PLATFORM
	    && _platformMap[Math.floor((gameObject.yPos-4)/MAX_TILE_SIZE)][gameObject.right] != PLATFORM)
	  {
	    gameObject.changeDirection ="2";
	    gameObject.direction = "up";
	    gameObject.vx = 0;
	    gameObject.vy = -5;
	  }
	}
	case "left":
	  if(_platformMap[gameObject.top][Math.floor((gameObject.xPos-6)/MAX_TILE_SIZE)] != PLATFORM
	    && _platformMap[gameObject.bottom][Math.floor((gameObject.xPos-6)/MAX_TILE_SIZE)] != PLATFORM)
	  {
	    gameObject.changeDirection = "2";
	    gameObject.direction = "left";
	    gameObject.vx = -5;
	    gameObject.vy = 0;
	  }
	case "right":
	  //trace(Math.floor((gameObject.yPos+gameObject.height+6)/MAX_TILE_SIZE)+","+Math.floor((gameObject.xPos+gameObject.width+6)/MAX_TILE_SIZE));
	  if(_platformMap[gameObject.top][Math.floor((gameObject.xPos+gameObject.width+6)/MAX_TILE_SIZE)] != PLATFORM
	    && _platformMap[gameObject.bottom][Math.floor((gameObject.xPos+gameObject.width+6)/MAX_TILE_SIZE)] != PLATFORM)
	  {
	    gameObject.changeDirection = "2";
	    gameObject.direction = "right";
	      gameObject.vx = 5;
	      gameObject.vy = 0;
	  }
	case "down":
	  if(_platformMap[Math.floor((gameObject.yPos+gameObject.height+4)/MAX_TILE_SIZE)][gameObject.left] != PLATFORM
	    && _platformMap[Math.floor((gameObject.yPos+gameObject.height+4)/MAX_TILE_SIZE)][gameObject.right] != PLATFORM)
	  {
	    gameObject.changeDirection = "2";
	    gameObject.direction = "down";
	    gameObject.vx = 0;
	    gameObject.vy = 5;
	  }
	default:
	  retval = true;

      }
      return retval;
    }
    public function findNewDirection(gameObject:TileModel)
    {
      var newDirection:String = "";
      //A random number between 1 and 4
      if(gameObject.changeDirection == "down")
      {
	newDirection = _HeartMapDown[gameObject.centerY][gameObject.centerX];
      }
      else if(gameObject.changeDirection == "up")
      {
	newDirection = _HeartMapUp[gameObject.centerY][gameObject.centerX];
      }
      else if(gameObject.changeDirection == "left")
      {
	newDirection = _HeartMapLeft[gameObject.centerY][gameObject.centerX];
      }
      else if(gameObject.changeDirection == "right")
      {
	newDirection = _HeartMapRight[gameObject.centerY][gameObject.centerX];
      }
//       var randomDirection:Int;
//       randomDirection = Math.ceil(Math.random() * 4);
//       trace(randomDirection);
// 
//       //2. Encourage the monster to choose up or down if
//       //it's currently moving left or right
//       if(gameObject.direction == "left"
//       || gameObject.direction == "right")
//       {
// 	if(randomDirection <= 2)
// 	{
// 	  newDirection = "up";
// 	}
// 	else
// 	{
// 	  newDirection = "down";
// 	} 
//       }
//       //if the object is currently moving up or down, make
//       //it move left or right
//       else
//       {
//         if(randomDirection <= 2)
// 	{
// 	  newDirection = "left";
// 	}
// 	else
// 	{
// 	  newDirection = "right";
// 	} 
//       }
      
      //Test the new direction and call this method recursively
      //if the direction runs the object into a wall
      switch(newDirection)
      {
        case "left":
          if(_platformMap[gameObject.mapRow][gameObject.mapColumn - 1] 
        		!= PLATFORM)
        	{
        	  gameObject.direction = newDirection;
      		  gameObject.vx = -5;
      		  gameObject.vy = 0;
      		}
      		else 
      		{
      		  //If the test hits a wall, assign this direction as
      		  //the object's new direction and test again.
      		  //(Assigning the new direction prevents the objects
      		  //from accidentally getting stuck in cul-de-sacs)
      		  gameObject.direction = newDirection;
      		  findRandomDirection(gameObject);
      		}
      	
      	case "right":	
      	  if(_platformMap[gameObject.mapRow][gameObject.mapColumn + 1] 
      		  != PLATFORM)
      		{
      		  gameObject.direction = newDirection;
    		    gameObject.vx = 5;
    		    gameObject.vy = 0;
    		  }
    		  else 
    		  {
    		    gameObject.direction = newDirection;
      		  findRandomDirection(gameObject);
      		}
      	
      	case "up":	
      	  if(_platformMap[gameObject.mapRow - 1][gameObject.mapColumn] 
      		  != PLATFORM)
      		{
      		  gameObject.direction = newDirection;
    		    gameObject.vx = 0;
    		    gameObject.vy = -5;
    		  }
    		  else
    		  {
    		    gameObject.direction = newDirection;
      		  findRandomDirection(gameObject);
      		}	
      	
      	case "down":
      	  if(_platformMap[gameObject.mapRow + 1][gameObject.mapColumn] 
      		  != PLATFORM)
      		{
      		  gameObject.direction = newDirection;
    		    gameObject.vx = 0;
    		    gameObject.vy = 5;
    		  }
    		  else
      		{
      		  gameObject.direction = newDirection;
      		  findRandomDirection(gameObject);
      		}
	 default:
	    gameObject.direction = newDirection;
	    findRandomDirection(gameObject);
      }
    }
    public function findRandomDirection(gameObject:TileModel)
    {
      if(_platformMap[gameObject.mapRow][gameObject.mapColumn - 1] != PLATFORM)
	{
	  gameObject.direction = "left";
	  gameObject.vx = -5;
	  gameObject.vy = 0;
	}
	else if(_platformMap[gameObject.mapRow][gameObject.mapColumn + 1] != PLATFORM)
	{
	  gameObject.direction = "right";
	    gameObject.vx = 5;
	    gameObject.vy = 0;
	}
	else if(_platformMap[gameObject.mapRow - 1][gameObject.mapColumn] != PLATFORM)
	{
	  gameObject.direction = "up";
	  gameObject.vx = 0;
	  gameObject.vy = -5;
	}
	else if(_platformMap[gameObject.mapRow + 1][gameObject.mapColumn] != PLATFORM)
	{
	  gameObject.direction = "down";
	  gameObject.vx = 0;
	  gameObject.vy = 5;
	}
	else
	{
	  gameObject.direction = "";
	  gameObject.vx = 0;
	  gameObject.vy = 0;
	}
    }

  private function drawGameObject
    (
      tileModel:TileModel, 
      screen:BitmapData
    )
    {
      var sourceRectangle:Rectangle = new Rectangle
	    (
	      tileModel.tileSheetColumn * MAX_TILE_SIZE+ tileModel.ImageX, 
	      tileModel.tileSheetRow * MAX_TILE_SIZE+ tileModel.ImageY, 
	      tileModel.ImageWidth, 
	      tileModel.ImageHeight
	    );
		
      if(tileModel.invincble > 0 && tileModel.invincble % 3 == 0)
      {
	return;
      }
      var destinationPoint:Point = new Point
      (
      tileModel.xPos-(tileModel.ImageXOffset), 
      tileModel.yPos-(tileModel.ImageYOffset)
      );

      screen.copyPixels
      (
      _tileSheetBitmapData, 
      sourceRectangle, 
      destinationPoint,
      null, null, true
      );
    }

  private function drawGunObject
    (
      tileModel:TileModel,
      sourceBitmapData:BitmapData,
      screen:BitmapData
    )
    {
      var sourceRectangle:Rectangle = new Rectangle
	    (
	      tileModel.tileSheetColumn * 100+ tileModel.ImageX, 
	      tileModel.tileSheetRow * 100+ tileModel.ImageY, 
	      tileModel.ImageWidth, 
	      tileModel.ImageHeight
	    );	
      var destinationPoint:Point = new Point
      (
      tileModel.xPos, 
      tileModel.yPos
      );

      screen.copyPixels
      (
      sourceBitmapData, 
      sourceRectangle, 
      destinationPoint,
      null, null, true
      );
    }
  public function clearEnemies()
  {
      for(pinkModel in _enemies)
      {
    	  //removeChild(pinkModel.HealthBar);
	  _enemies.remove(pinkModel);
      }
  }
  public function UnLoad()
  {
      clearEnemies();
      for(pinkModel in _enemiesReserve)
      {
	  _enemiesReserve.remove(pinkModel);
      }
      flash.Lib.current.removeChild(this);
      //removeChild(MainHealthBar);
      if(_bossModel != null)
      {
	removeChild(_bossHealth);
      }
      //_MainCharacterController = null;

  }

public function checkWin()
{
//   var pinkModelCount = 0;
//   for(pinkModel in _enemies)
//   {
//     pinkModelCount++;
//   }
//   if(pinkModelCount < maxEnemiesOnScreen)
//   {
//     var tempModel = _enemiesReserve.pop();
//     if(tempModel != null)
//     {
// 	addChild(tempModel.HealthBar);
//       tempModel.model.MaxHealth = 5*Difficulty;
//       tempModel.model.health = 5*Difficulty;
//       _enemies.add(tempModel);
//       pinkModelCount++;
//     }
//   }
//  return pinkModelCount <= 0;
  return false;
}

function OnEnter(e:flash.events.Event)
{
    try
    {
      if(checkWin())
      {	
	UnLoad();
	this.removeEventListener(Event.ENTER_FRAME, OnEnter);
	dispatchEvent(new Event("LevelFinished"));return;
      }
      if(Pause == "Paused")
      {
	return;
      }
      //Clear the stage bitmap from the previous frame so that it's
      //blank when you add the new tile positions
      _foregroundBitmapData.fillRect(_foregroundBitmapData.rect, 0);
      //Set up the camera to focus on the cat
      _camera.x = _boxModel.xPos-Constants.flashWidth*0.5;
      _camera.y = 0;
      
      //Check the camera's game world boundaries
      //Left
      if(_camera.x < 0)
      {
	_camera.x = 0;
      }
      
      //Right
      if(_camera.x > (MAP_COLUMNS * MAX_TILE_SIZE) 
	- Constants.flashWidth)
      {
	_camera.x = (MAP_COLUMNS * MAX_TILE_SIZE) - Constants.flashWidth;
      }
      
      //Bottom
      if(_camera.y > (MAP_ROWS * MAX_TILE_SIZE) - Constants.flashHeight)
      {
	_camera.y = (MAP_ROWS * MAX_TILE_SIZE) - Constants.flashHeight;
      }
      
      //Top
      if(_camera.y < 0)
      {
	_camera.y = 0;
      }
    
      //Update the box's Model
      _boxModel.update();
      _collisionController.platformCollision(_boxModel,_platformMap,MAX_TILE_SIZE,PLATFORM);
      //if Shoting
//       shotVector.update(0, 0,0,0);
//       	var y2 =  _boxModel.yPos + _boxModel.height/2;
// 	var y1 = mouseY;
// 	
// 	var x2 = _boxModel.xPos +_boxModel.width/2;
// 	var x1 = mouseX+_camera.x;
// 	var m = (y2 - y1 )/(x2 - x1);
// 	var b = (y2) - m*(x2);
// 	var testVector = new VectorModel();
// 	testVector.update(x2, y2,x1,y1);

    _collisionMap = [[]];
    for(row in 0...MAP_ROWS)
    {
      _collisionMap[row] = [];
      for(column in 0...MAP_ROWS)	
      {
	_collisionMap[row][column] = new List<TileModel>();
      }
    }
    for(enemy in _enemies)
    {
	_collisionMap[enemy.model.mapRow][enemy.model.mapColumn].add(enemy.model);
	enemy.model.update();
	     if (enemy.model.xPos + (enemy.model.width) > maxX)
      {
	enemy.model.setX = maxX - (enemy.model.width);
	enemy.model.vx = 0;
      }
      else if (enemy.model.xPos < minX)
      {
	      enemy.model.setX = minX;
	      enemy.model.vx = 0;
      }
      if (enemy.model.yPos < 0)
      {
	      enemy.model.setY = 0;
	      enemy.model.vy = 0;
      }

      else if (enemy.model.yPos + enemy.model.height > Constants.flashHeight && enemy.model.vy > 0)
      {
	      enemy.model.setY = Constants.flashHeight - enemy.model.height;
	      enemy.model.vy = 0;
	      enemy.model.jumping = 0;
      } 
	drawGameObject(enemy.model,_foregroundBitmapData);
    }
    //_collisionMap[_boxModel.mapRow][_boxModel.mapColumn].add(_boxModel);
	for(column in -1...2)
	{
	  for(row in -1...2)
	  {
	    if(_boxModel.mapRow + row < _collisionMap.length &&
	       _boxModel.mapRow + row >= 0 &&
	       _boxModel.mapColumn + column < _collisionMap[0].length &&
	       _boxModel.mapColumn + column >= 0)
	    {		
	      	for(model in _collisionMap[_boxModel.mapRow + row ][_boxModel.mapColumn + column])
		{
		  //collision
		}
	    }
	  }
	}
      //Stop the box at the stage boundaries
      //StageBoundaries.stopBitmap(_boxModel, stage);
      maxX = Math.min(maxX, MAP_COLUMNS * MAX_TILE_SIZE);
      if (_boxModel.xPos + (_boxModel.width) > maxX)
      {
	_boxModel.setX = maxX - (_boxModel.width);
	_boxModel.vx = 0;
      }
      else if (_boxModel.xPos < minX)
      {
	      _boxModel.setX = minX;
	      _boxModel.vx = 0;
      }
      if (_boxModel.yPos < 0)
      {
	      _boxModel.setY = 0;
	      _boxModel.vy = 0;
      }
      else if (_boxModel.yPos + _boxModel.height > Constants.flashHeight && _boxModel.vy > 0)
      {
	      _boxModel.setY = Constants.flashHeight - _boxModel.height;
	      _boxModel.vy = 0;
	      _boxModel.jumping = 0;
      } 
      
 
      //Check for collisions with the platforms
//       _collisionController.platformCollision
// 	(_boxModel, _platformMap, MAX_TILE_SIZE, PLATFORM);

      //Blit the box on the foreground bitmap
      
      drawGameObject(_boxModel, _foregroundBitmapData);

      //Scroll the game world
      _foregroundBitmap.scrollRect = _camera;
      _backgroundBitmap.scrollRect = _camera;

      //_gunView.scrollRect = _camera;
      //drawGunObject(_gunModel,_currentGunBitmapData, _foregroundBitmapData); 
    }
catch(err:Dynamic)
    {
    trace(err.message);
    }
}
}